using System;
using System.IO;
using System.Windows.Forms;
using Slaks.Analysis.Forms;
using Slaks.DocumentSerialization.Dictionary;
using Slaks.DocumentSerialization.Document;
using Slaks.DocumentSerialization.Document.Wordnet;
using Slaks.Graphs;
using Slaks.Graphs.Algorithms;
using Slaks.Graphs.GraphBuilder;
using Slaks.Graphs.GraphBuilder.Wordnet;
using Slaks.VectorBasics;
using Slaks.VectorBasics.Algorithms;
using Slaks.VectorBasics.Containers;
using Slaks.VectorBasics.VectorBuilder;

namespace Slaks.Analysis.Mediators
{
	public class AnalysisMediator
	{
		private Form m_parent;

		public AnalysisMediator(Form parent)
		{
			m_parent = parent;
		}

		public void RunVectorSingle(string file, string localDictionaryFile, BuilderType representation, DistanceAlgorithm distanceAlgorithm)
		{
			//check whether the local dictionary file exists
			if (FileExists(localDictionaryFile) == false) throw new Exception("Provide valid filename for local dictionary file");
			WordnetDocument document = Xml2WordnetDocument.ReadXml(file);
			DictionaryMap dictionaryMap = DictionaryInfo.ReadXml(localDictionaryFile);
			if (dictionaryMap == null) throw new Exception("Some problem occurred with dictionary or with the parsing");

			
			Vector vector = Slaks.VectorBasics.VectorBuilder.WordnetStandardRepresentation.Build(document, dictionaryMap);

			InformationADT information = new InformationADT();
			information.DistanceAlgorithm = distanceAlgorithm.ToString();
			information.Representation = representation.ToString();
			information.TypeSize = dictionaryMap.Count; // size of the dictionary;

			new VectorSingleView(document, vector, information);

		}

		public void RunVectorComparison(string fileOne, string fileTwo, string localDictionaryFile, BuilderType representation, DistanceAlgorithm distanceAlgorithm)
		{
			//check whether the local dictionary file exists
			if (FileExists(localDictionaryFile) == false) throw new Exception("Provide valid filename for local dictionary file");
			WordnetDocument documentOne = Xml2WordnetDocument.ReadXml(fileOne);
			WordnetDocument documentTwo = Xml2WordnetDocument.ReadXml(fileTwo);
			DictionaryMap dictionaryMap = DictionaryInfo.ReadXml(localDictionaryFile);
			if (dictionaryMap == null) throw new Exception("Some problem occurred with dictionary or with the parsing");

			Vector vectorOne, vectorTwo;
			if (representation != BuilderType.StandardRepresentationSchenker ||
				representation != BuilderType.StandardRepresentationSlaks) throw new Exception("Only standard representation is acceptible for vectors");
			vectorOne = Slaks.VectorBasics.VectorBuilder.WordnetStandardRepresentation.Build(documentOne, dictionaryMap);
			vectorTwo = Slaks.VectorBasics.VectorBuilder.WordnetStandardRepresentation.Build(documentTwo, dictionaryMap);

			double mutualDistance;

			if (distanceAlgorithm == DistanceAlgorithm.WordnetVector) mutualDistance = VectorDistances.GetWordnet(vectorOne, vectorTwo);
			else if (distanceAlgorithm == DistanceAlgorithm.Cosine) mutualDistance = VectorDistances.GetCosinus(vectorOne,vectorTwo);
			else throw new Exception("Only WordnetVector and Cosine distance algorithms are acceptible!");

			InformationADT information = new InformationADT();
			information.DistanceAlgorithm = distanceAlgorithm.ToString();
			information.Representation = representation.ToString();
			information.MutualDistance = mutualDistance;
			information.TypeSize = dictionaryMap.Count; // size of the dictionary;

			Vector commonVector = this.GetCommonVector(vectorOne, vectorTwo);

			new VectorComparisonView(documentOne, documentTwo, vectorOne, vectorTwo, commonVector, information);

		}

		public void RunGraphSingle(string file, int graphSize, BuilderType representationType, int distanceValue, DistanceAlgorithm distanceAlgorithm)
		{
			WordnetDocument document = Xml2WordnetDocument.ReadXml(file);
			Graph graph = null;
			IWordnetRepresentation representation = WordnetGraphBuilderFactory.GetGraphBuilder(representationType);
			if (representation == null) throw new Exception("No such representation : " + representationType);

			/*
			if (representationType == BuilderType.NDistanceRepresentationSchenker ||
				representationType == BuilderType.NDistanceRepresentationSlaks ||
				representationType == BuilderType.NSimpleDistanceRepresentationSchenker ||
				representationType == BuilderType.NSimpleDistanceRepresentationSlaks
				)
			{
				graph = representation.Build(document, graphSize, distanceValue);
			}
			else
			{
				graph = representation.Build(document, graphSize);
			}
			*/

			if (representationType == BuilderType.WordnetStandardRepresentation
				   ||
				  representationType == BuilderType.WordnetRawFrequencyRepresentation) graph = representation.Build(document, graphSize);
			else throw new Exception("Currently only WordnetStandardRepresentation and WordnetRawFrequencyRepresentation are available");

			InformationADT information = new InformationADT();
			information.Representation = representationType.ToString();
			information.DistanceValue = distanceValue;
			information.DistanceAlgorithm = distanceAlgorithm.ToString();
			information.TypeSize = graphSize;
			new GraphSingleView(document, graph, information);
		}

		public void RunGraphComparison(string fileOne, string fileTwo, int graphSize, BuilderType representationType, int distanceValue, DistanceAlgorithm distanceAlgorithm)
		{
			WordnetDocument documentOne = Xml2WordnetDocument.ReadXml(fileOne);
			WordnetDocument documentTwo = Xml2WordnetDocument.ReadXml(fileTwo);
			Graph graphOne = null;
			Graph graphTwo = null;
			Graph commonGraph = null;
			double mutualDistance = Double.NaN;
			IWordnetRepresentation representation = WordnetGraphBuilderFactory.GetGraphBuilder(representationType);
			if (representation == null) throw new Exception("No such representation : " + representationType);

			graphOne = WordnetGraphBuilderMediator.BuildAdaptor(documentOne, representation, representationType, graphSize, distanceValue);
			graphTwo = WordnetGraphBuilderMediator.BuildAdaptor(documentTwo, representation, representationType, graphSize, distanceValue);

			if (representationType == BuilderType.WordnetStandardRepresentation)
			{
				if (distanceAlgorithm == DistanceAlgorithm.WordnetGraph)
				{
					mutualDistance = WordnetGraphDistance.GetDistance(graphOne, graphTwo);
				}
				else if (distanceAlgorithm == DistanceAlgorithm.Mcs)
				{
					mutualDistance = GraphDistances.DistMCS4VertexEdgeCount(graphOne,graphTwo);
					commonGraph = MaxCommonSubGraphVertexEdgeCount.GetMCS(graphOne,graphTwo);
				}
				else throw new Exception("Only WordnetGraph and Mcs distances algorithms allowed");
			}
			else if (representationType == BuilderType.WordnetRawFrequencyRepresentation)
			{
				if (distanceAlgorithm == DistanceAlgorithm.WordnetGraph)
				{
					mutualDistance = WordnetGraphDistance.GetDistance(graphOne, graphTwo);
				}
				else if (distanceAlgorithm == DistanceAlgorithm.Mcs)
				{
					mutualDistance = GraphDistances.DistMCS4VertexEdgeFrequency(graphOne,graphTwo);
					commonGraph = MaxCommonSubGraphVertexEdgeFrequency.GetMCS(graphOne,graphTwo);
				}
				else throw new Exception("Only WordnetGraph and Mcs distances algorithms allowed");
			}
			else throw new Exception("Only WordnetStandardRepresentation and WordnetRawFrequencyRepresentation are allowed");

			InformationADT information = new InformationADT();
			information.Representation = representation.ToString();
			information.DistanceValue = distanceValue;
			information.DistanceAlgorithm = distanceAlgorithm.ToString();
			information.TypeSize = graphSize;
			information.MutualDistance = mutualDistance;
			new GraphComparisonView(documentOne, documentTwo, graphOne, graphTwo, commonGraph, information);
		}

		private bool FileExists(string file)
		{
			return File.Exists(file);
		}

		private DictionaryMap GetDictionary(long[] ids)
		{
			DictionaryMap dictionaryMap = new DictionaryMap();
			object obj = new object();
			foreach (long id in ids)
			{
				dictionaryMap.Add(id, obj);
			}
			return dictionaryMap;
		}

		private Vector GetCommonVector(Vector vectorOne, Vector vectorTwo)
		{
			Vector commonVector = new Vector("Common vector");

			vectorOne.SortVectorItems();
			vectorTwo.SortVectorItems();

			VectorItemList itemListOne = vectorOne.GetVectorItemList();
			VectorItemList itemListTwo = vectorTwo.GetVectorItemList();

			int indexOne = 0;
			int indexTwo = 0;

			while (indexOne < itemListOne.Count && indexTwo < itemListTwo.Count)
			{
				if (itemListOne[indexOne].GetId() < itemListTwo[indexTwo].GetId()) indexOne++;
				else if (itemListOne[indexOne].GetId() > itemListTwo[indexTwo].GetId()) indexTwo++;
				else
				{
					commonVector.CreateAddVectorItem(itemListOne[indexOne].GetId());
					indexOne++;
					indexTwo++;
				}
			}

			return commonVector;
		}

	}


}